package com.enjoy.photoview.learn;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.OverScroller;

import androidx.annotation.Nullable;

import com.enjoy.photoview.Utils;

/**
 * @ProjectName : PhotoView
 * @Author : Jason
 * @Time : 2021/7/19 14:13
 * @Description : 文件描述
 */
public class LearnPhotoView extends View {
    private static final String TAG = LearnPhotoView.class.getSimpleName();
    private Bitmap bitmap;
    private Paint paint;
    private float originalOffsetX;
    private float originalOffsetY;
    private float smallScale;
    //越过的缩放因子
    private float OVER_SCALE_FACTOR = 1.5f;
    private float bigScale;
    private float currentScale;
    private GestureDetector gestureDetector;
    //手指滚动的X偏移和Y偏移
    private float offsetX;
    private float offsetY;
    //具有能够超出滚动边界的能力
    private OverScroller overScroller;
    //是否放大
    private boolean isEnlarge;
    private ScaleGestureDetector scaleGestureDetector;
    private ObjectAnimator scaleAnimator;

    public LearnPhotoView(Context context) {
        this(context, null);
    }

    public LearnPhotoView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public LearnPhotoView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, -1);
    }

    public LearnPhotoView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        bitmap = Utils.getPhoto(getResources(), 600);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        gestureDetector = new GestureDetector(getContext(), new PhotoGestureDetector());
        scaleGestureDetector = new ScaleGestureDetector(getContext(), new PhotoScaleGestureListener());
        overScroller = new OverScroller(getContext(), new AccelerateDecelerateInterpolator());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //计算点击放大时偏移量的因子
        float scaleFaction = (currentScale - smallScale) / (bigScale - smallScale);
        Log.d(TAG, "scaleFaction = " + scaleFaction);
        Log.d(TAG, "offsetX * scaleFaction = " + offsetX * scaleFaction);
        if (scaleFaction >= 0) {//为了缩小时恢复到原位，不发生偏移
            // 当前放大比例为small时，scaleFaction = 0，不偏移
            canvas.translate(offsetX * scaleFaction, offsetY * scaleFaction);
        }
        canvas.scale(currentScale, currentScale, getWidth() / 2, getHeight() / 2);
        Log.d(TAG, "originalOffsetX = " + originalOffsetX + "  originalOffsetY=" + originalOffsetY);
        canvas.drawBitmap(bitmap, originalOffsetX, originalOffsetY, paint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //计算将图片摆放到视图中央的左上角坐标
        originalOffsetX = (getWidth() - bitmap.getWidth()) / 2f;
        originalOffsetY = (getHeight() - bitmap.getHeight()) / 2f;

        if (bitmap.getWidth() / bitmap.getHeight() > getWidth() / getHeight()) {
            //宽占满
            smallScale = (float) getWidth() / bitmap.getWidth();
            bigScale = (float) getHeight() / bitmap.getHeight() * OVER_SCALE_FACTOR;
        } else {
            //高占满
            smallScale = (float) getHeight() / bitmap.getHeight();
            bigScale = (float) getWidth() / bitmap.getWidth() * OVER_SCALE_FACTOR;
        }
        currentScale = smallScale;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 响应事件以双指缩放优先
        boolean result = scaleGestureDetector.onTouchEvent(event);
        if (!scaleGestureDetector.isInProgress()) {
            result = gestureDetector.onTouchEvent(event);
        }
        return result;
    }

    private void fixOffsets() {
        offsetX = Math.min(offsetX, (bitmap.getWidth() * bigScale - getWidth()) / 2);
        offsetX = Math.max(offsetX, -(bitmap.getWidth() * bigScale - getWidth()) / 2);
        offsetY = Math.min(offsetY, (bitmap.getHeight() * bigScale - getHeight()) / 2);
        offsetY = Math.max(offsetY, -(bitmap.getHeight() * bigScale - getHeight()) / 2);
    }

    class FlingRunner implements Runnable {

        @Override
        public void run() {
            //当获取到新的位置
            if (overScroller.computeScrollOffset()) {
                offsetX = overScroller.getCurrX();
                offsetY = overScroller.getCurrY();
                invalidate();
                // 下一帧动画的时候执行
                postOnAnimation(this);
            }
        }
    }

    /**
     * 缩放属性动画
     *
     * @return
     */
    private ObjectAnimator getScaleAnimation() {
        if (scaleAnimator == null) {
            scaleAnimator = ObjectAnimator.ofFloat(this, "currentScale", 0);
        }
        if (currentScale < smallScale) {
            scaleAnimator.setFloatValues(currentScale, bigScale);
        } else if (currentScale == smallScale || currentScale == bigScale) {
            scaleAnimator.setFloatValues(smallScale, bigScale);
        } else if (currentScale > smallScale && currentScale < bigScale) {//放大到还不是最大的情况下
            scaleAnimator.setFloatValues(smallScale, currentScale);
        }
        scaleAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        return scaleAnimator;
    }

    public float getCurrentScale() {
        return currentScale;
    }

    public void setCurrentScale(float currentScale) {
        this.currentScale = currentScale;
        invalidate();
    }

    //双击只关注放大
    class PhotoGestureDetector extends GestureDetector.SimpleOnGestureListener {

        private final String TAG = PhotoGestureDetector.class.getSimpleName();

        // up 触发，单击或者双击的第一次会触发 --- up时，如果不是双击的第二次点击，不是长按，则触发
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            Log.d(TAG, "onSingleTapUp");
            return super.onSingleTapUp(e);
        }

        // 长按 -- 默认300ms触发
        @Override
        public void onLongPress(MotionEvent e) {
            Log.d(TAG, "onLongPress");
            super.onLongPress(e);
        }

        /**
         * 滚动 -- move
         *
         * @param e1        手指按下
         * @param e2        当前的
         * @param distanceX 旧位置 - 新位置
         * @param distanceY
         * @return
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            Log.d(TAG, "onScroll :distanceX=" + distanceX + "  distanceY=" + distanceY);
            if (isEnlarge && currentScale > smallScale) {
                //向右滑动 distanceX为负数  向下滑动distanceY为负数
                offsetX -= distanceX;
                offsetY -= distanceY;
                fixOffsets();
                invalidate();
            }
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        /**
         * up 惯性滑动 -- 大于50dp/s
         *
         * @param velocityX x轴方向运动速度（像素/s）
         * @param velocityY
         * @return
         */
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            Log.d(TAG, "onFling");
            if (isEnlarge&&currentScale > smallScale) {
                //overX overY可以超出300px
                overScroller.fling((int) offsetX, (int) offsetY, (int) velocityX, (int) velocityY,
                        -(int) (bitmap.getWidth() * bigScale - getWidth()) / 2,
                        (int) (bitmap.getWidth() * bigScale - getWidth()) / 2,
                        -(int) (bitmap.getHeight() * bigScale - getHeight()) / 2,
                        (int) (bitmap.getHeight() * bigScale - getHeight()) / 2,
                        300, 300);
                postOnAnimation(new FlingRunner());
            }
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        // 延时100ms触发 -- 处理点击效果
        @Override
        public void onShowPress(MotionEvent e) {
            Log.d(TAG, "onShowPress");
            super.onShowPress(e);
        }

        // 只需要关注 onDown 的返回值即可
        @Override
        public boolean onDown(MotionEvent e) {
            Log.d(TAG, "onDown");
            return true;
        }

        // 双击的第二次点击down时触发。双击的触发时间 -- 40ms到300ms之间
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            Log.d(TAG, "onDoubleTap");
            isEnlarge = !isEnlarge;
            if (isEnlarge) {
                offsetX = (e.getX() - getWidth() / 2f) -
                        (e.getX() - getWidth() / 2f) * bigScale / smallScale;
                offsetY = (e.getY() - getHeight() / 2f) -
                        (e.getY() - getHeight() / 2f) * bigScale / smallScale;
                fixOffsets();
                getScaleAnimation().start();
            } else {
                getScaleAnimation().reverse();
            }
            return super.onDoubleTap(e);
        }

        // 双击的第二次down、move、up 都触发
        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            Log.d(TAG, "onDoubleTapEvent");
            return super.onDoubleTapEvent(e);
        }

        // 单击按下时触发，双击时不触发，down，up时都可能触发
        // 延时300ms触发TAP事件
        // 300ms以内抬手 -- 才会触发TAP -- onSingleTapConfirmed
        // 300ms 以后抬手 --- 不是双击不是长按，则触发
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.d(TAG, "onSingleTapConfirmed");
            return super.onSingleTapConfirmed(e);
        }

        @Override
        public boolean onContextClick(MotionEvent e) {
            Log.d(TAG, "onContextClick");
            return super.onContextClick(e);
        }
    }

    /**
     * 缩放手势监听
     */
    class PhotoScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {

        private final String TAG = PhotoScaleGestureListener.class.getSimpleName();
        float initScale;

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            //(currentScale > smallScale && !isEnlarge)是双指拉大的
            //(currentScale == smallScale && !isEnlarge)正常显示 宽度占满
            if ((currentScale > smallScale && !isEnlarge)
                    || (currentScale == smallScale && !isEnlarge)) {
                isEnlarge = !isEnlarge;
            }
           // currentScale < smallScale && isEnlarge  缩小到图片的正常宽度 图片宽度小于view宽度
            if (currentScale < smallScale && isEnlarge) {
                isEnlarge = !isEnlarge;
            }
            //detector.getScaleFactor()每次点下去初始是1  不断增大或缩小
            Log.d(TAG, "isEnlarge = " + isEnlarge);
            float scale = initScale * detector.getScaleFactor();
            if (scale * bitmap.getWidth() >= bitmap.getWidth()
                    && scale <= bigScale) {
                // 缩放因子
                currentScale = initScale * detector.getScaleFactor();
                Log.d(TAG, "currentScale = " + currentScale);
            }
            invalidate();
            return false;
        }

        /**
         * 缩放开始  初始缩放就是当前的缩放值
         *
         * @param detector
         * @return
         */
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            initScale = currentScale;
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {

        }
    }
}
